# _*_ coding:utf-8 _*_
# 开发团队: Mavericks
# 开发人员：Maverick·Ming
# 开发IDE： PyCharm
#   项目名：HelloWorld
#   文件名：6.12 多态.py
# 开发时间：2021/3/26 18:34

# 多态，面向对象三大特征之一（封装、继承、多态）
# 意思是，多种形态（多种品种），如Dog类有柴犬、哈士奇、藏獒、斗牛犬、中华田园犬等等多种形态
# 一个对象可以以不同的形态去呈现

# 定义两个类
class A:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name


class B:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name


a = A('青苹果')
b = B('红苹果')


# 定义一个工具人C类
class C:

    def __len__(self):
        return 10


c = C()


# 定义一个函数
# 对于say_hello()而言，只要obj中有name属性get set方法，obj就可以作为参数传递
# 这个函数say_hello并不考虑对象的类型，只要有name属性即可正常运行
def say_hello(obj):
    print('Hello!%s' % obj.name)


# say_hello(a)
# say_hello(B)
# say_hello(c)  # 结果：AttributeError: 'C' object has no attribute 'name'


def say_hello2(obj):
    # 做类型检查
    if isinstance(obj, A):
        print('Hello！%s'%obj.name)


say_hello2(a)
say_hello2(B)  # 结果：不显示
# 在say_hello2中我们做了类型检查，只有obj的父类是A类才打印输出
# 这样的做法，违反了多态的函数，只适用于一种类型的对象，无法处理其他类型对象
# 这样导致了该类say hello2函数的适应性非常的差
# 为了适应其他类型，得一个个添加检查适应

# 鸭子类型
# 如果一个东西，走路像鸭子，叫声像鸭子，那么它就是鸭子

# len()
l = [1, 2 ,3]  # 列表
s = 'hello'  # 字符串
print(len(l), '\t', len(s))

# 之所以一个对象（无论是列表还是字符串）能通过len()获取长度，是因为对象中具有一个特殊方法__len__()
# 换句话说，只要对象中具有__len__特殊方法，就可以通过len()来获取它的长度

print(len(c))  # c因为继承了父类__len__的方法，所以会有长度